package com.smart.community.region.service.impl;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.smart.community.feign.region.dto.AddressInfoDTO;
import com.smart.community.region.entity.Building;
import com.smart.community.region.entity.Community;
import com.smart.community.region.entity.Household;
import com.smart.community.region.entity.Region;
import com.smart.community.region.entity.Unit;
import com.smart.community.region.mapper.BuildingMapper;
import com.smart.community.region.mapper.CommunityMapper;
import com.smart.community.region.mapper.HouseholdMapper;
import com.smart.community.region.mapper.RegionMapper;
import com.smart.community.region.mapper.UnitMapper;
import com.smart.community.region.service.IAddressService;

import lombok.extern.slf4j.Slf4j;

/**
 * 地址服务实现类
 * 提供地址查询和构建功能，支持缓存
 * 
 * @author Wu.Liang
 * @since 2025-01-30
 */
@Slf4j
@Service
public class AddressServiceImpl implements IAddressService {

    @Autowired
    private HouseholdMapper householdMapper;

    @Autowired
    private UnitMapper unitMapper;

    @Autowired
    private BuildingMapper buildingMapper;

    @Autowired
    private CommunityMapper communityMapper;

    @Autowired
    private RegionMapper regionMapper;

    @Override
    @Cacheable(value = "address:byHouseholdId", key = "#householdId", unless = "#result == null")
    public AddressInfoDTO getAddressByHouseholdId(Long householdId) {
        log.info("根据房户ID获取详细地址，房户ID：{}", householdId);
        
        try {
            // 1. 查询房户信息
            Household household = householdMapper.selectById(householdId);
            if (household == null) {
                log.warn("房户不存在，房户ID：{}", householdId);
                return null;
            }

            // 2. 查询单元信息
            Unit unit = unitMapper.selectById(household.getUnitId());
            if (unit == null) {
                log.warn("单元不存在，单元ID：{}", household.getUnitId());
                return null;
            }

            // 3. 查询楼栋信息
            Building building = buildingMapper.selectById(household.getBuildingId());
            if (building == null) {
                log.warn("楼栋不存在，楼栋ID：{}", household.getBuildingId());
                return null;
            }

            // 4. 查询社区信息
            Community community = communityMapper.selectById(building.getCommunityId());
            if (community == null) {
                log.warn("社区不存在，社区ID：{}", building.getCommunityId());
                return null;
            }

            // 5. 构建区域地址
            String regionAddress = buildRegionAddress(community.getRegionId());

            // 6. 构建完整地址
            String fullAddress = buildFullAddress(regionAddress, community.getCommunityName(), 
                    building.getBuildingNo(), unit.getUnitNo(), household.getRoomNumber());

            // 7. 构建返回对象
            AddressInfoDTO addressInfo = new AddressInfoDTO();
            addressInfo.setFullAddress(fullAddress);
            addressInfo.setRegionId(community.getRegionId());
            addressInfo.setRegionName(getRegionName(community.getRegionId()));
            addressInfo.setCommunityId(community.getId());
            addressInfo.setCommunityName(community.getCommunityName());
            addressInfo.setBuildingId(building.getId());
            addressInfo.setBuildingName(building.getBuildingName());
            addressInfo.setBuildingNo(building.getBuildingNo());
            addressInfo.setUnitId(unit.getId());
            addressInfo.setUnitName(unit.getUnitName());
            addressInfo.setUnitNo(unit.getUnitNo());
            addressInfo.setHouseholdId(household.getId());
            addressInfo.setRoomNumber(household.getRoomNumber());

            log.info("根据房户ID获取详细地址成功，房户ID：{}，地址：{}", householdId, fullAddress);
            return addressInfo;

        } catch (Exception e) {
            log.error("根据房户ID获取详细地址失败，房户ID：{}", householdId, e);
            return null;
        }
    }

    @Override
    @Cacheable(value = "address:byUnitId", key = "#unitId", unless = "#result == null")
    public AddressInfoDTO getAddressByUnitId(Long unitId) {
        log.info("根据单元ID获取详细地址，单元ID：{}", unitId);
        
        try {
            // 1. 查询单元信息
            Unit unit = unitMapper.selectById(unitId);
            if (unit == null) {
                log.warn("单元不存在，单元ID：{}", unitId);
                return null;
            }

            // 2. 查询楼栋信息
            Building building = buildingMapper.selectById(unit.getBuildingId());
            if (building == null) {
                log.warn("楼栋不存在，楼栋ID：{}", unit.getBuildingId());
                return null;
            }

            // 3. 查询社区信息
            Community community = communityMapper.selectById(building.getCommunityId());
            if (community == null) {
                log.warn("社区不存在，社区ID：{}", building.getCommunityId());
                return null;
            }

            // 4. 构建区域地址
            String regionAddress = buildRegionAddress(community.getRegionId());

            // 5. 构建完整地址
            String fullAddress = buildFullAddress(regionAddress, community.getCommunityName(), 
                    building.getBuildingNo(), unit.getUnitNo(), null);

            // 6. 构建返回对象
            AddressInfoDTO addressInfo = new AddressInfoDTO();
            addressInfo.setFullAddress(fullAddress);
            addressInfo.setRegionId(community.getRegionId());
            addressInfo.setRegionName(getRegionName(community.getRegionId()));
            addressInfo.setCommunityId(community.getId());
            addressInfo.setCommunityName(community.getCommunityName());
            addressInfo.setBuildingId(building.getId());
            addressInfo.setBuildingName(building.getBuildingName());
            addressInfo.setBuildingNo(building.getBuildingNo());
            addressInfo.setUnitId(unit.getId());
            addressInfo.setUnitName(unit.getUnitName());
            addressInfo.setUnitNo(unit.getUnitNo());

            log.info("根据单元ID获取详细地址成功，单元ID：{}，地址：{}", unitId, fullAddress);
            return addressInfo;

        } catch (Exception e) {
            log.error("根据单元ID获取详细地址失败，单元ID：{}", unitId, e);
            return null;
        }
    }

    @Override
    @Cacheable(value = "address:byBuildingId", key = "#buildingId", unless = "#result == null")
    public AddressInfoDTO getAddressByBuildingId(Long buildingId) {
        log.info("根据楼栋ID获取详细地址，楼栋ID：{}", buildingId);
        
        try {
            // 1. 查询楼栋信息
            Building building = buildingMapper.selectById(buildingId);
            if (building == null) {
                log.warn("楼栋不存在，楼栋ID：{}", buildingId);
                return null;
            }

            // 2. 查询社区信息
            Community community = communityMapper.selectById(building.getCommunityId());
            if (community == null) {
                log.warn("社区不存在，社区ID：{}", building.getCommunityId());
                return null;
            }

            // 3. 构建区域地址
            String regionAddress = buildRegionAddress(community.getRegionId());

            // 4. 构建完整地址
            String fullAddress = buildFullAddress(regionAddress, community.getCommunityName(), 
                    building.getBuildingNo(), null, null);

            // 5. 构建返回对象
            AddressInfoDTO addressInfo = new AddressInfoDTO();
            addressInfo.setFullAddress(fullAddress);
            addressInfo.setRegionId(community.getRegionId());
            addressInfo.setRegionName(getRegionName(community.getRegionId()));
            addressInfo.setCommunityId(community.getId());
            addressInfo.setCommunityName(community.getCommunityName());
            addressInfo.setBuildingId(building.getId());
            addressInfo.setBuildingName(building.getBuildingName());
            addressInfo.setBuildingNo(building.getBuildingNo());

            log.info("根据楼栋ID获取详细地址成功，楼栋ID：{}，地址：{}", buildingId, fullAddress);
            return addressInfo;

        } catch (Exception e) {
            log.error("根据楼栋ID获取详细地址失败，楼栋ID：{}", buildingId, e);
            return null;
        }
    }

    @Override
    @Cacheable(value = "address:byCommunityId", key = "#communityId", unless = "#result == null")
    public AddressInfoDTO getAddressByCommunityId(Long communityId) {
        log.info("根据社区ID获取详细地址，社区ID：{}", communityId);
        
        try {
            // 1. 查询社区信息
            Community community = communityMapper.selectById(communityId);
            if (community == null) {
                log.warn("社区不存在，社区ID：{}", communityId);
                return null;
            }

            // 2. 构建区域地址
            String regionAddress = buildRegionAddress(community.getRegionId());

            // 3. 构建完整地址
            String fullAddress = buildFullAddress(regionAddress, community.getCommunityName(), 
                    null, null, null);

            // 4. 构建返回对象
            AddressInfoDTO addressInfo = new AddressInfoDTO();
            addressInfo.setFullAddress(fullAddress);
            addressInfo.setRegionId(community.getRegionId());
            addressInfo.setRegionName(getRegionName(community.getRegionId()));
            addressInfo.setCommunityId(community.getId());
            addressInfo.setCommunityName(community.getCommunityName());

            log.info("根据社区ID获取详细地址成功，社区ID：{}，地址：{}", communityId, fullAddress);
            return addressInfo;

        } catch (Exception e) {
            log.error("根据社区ID获取详细地址失败，社区ID：{}", communityId, e);
            return null;
        }
    }

    @Override
    @Cacheable(value = "address:byHouseholdIds", key = "#householdIds.hashCode()", unless = "#result == null || #result.isEmpty()")
    public List<AddressInfoDTO> getAddressesByHouseholdIds(List<Long> householdIds) {
        log.info("根据房户ID列表获取详细地址，房户ID列表：{}", householdIds);
        
        try {
            List<AddressInfoDTO> addressInfoList = new ArrayList<>();
            
            for (Long householdId : householdIds) {
                AddressInfoDTO addressInfo = getAddressByHouseholdId(householdId);
                if (addressInfo != null) {
                    addressInfoList.add(addressInfo);
                }
            }
            
            log.info("根据房户ID列表获取详细地址成功，房户ID列表：{}，获取到{}个地址", householdIds, addressInfoList.size());
            return addressInfoList;

        } catch (Exception e) {
            log.error("根据房户ID列表获取详细地址失败，房户ID列表：{}", householdIds, e);
            return new ArrayList<>();
        }
    }

    @Override
    @Cacheable(value = "address:byUnitIds", key = "#unitIds.hashCode()", unless = "#result == null || #result.isEmpty()")
    public List<AddressInfoDTO> getAddressesByUnitIds(List<Long> unitIds) {
        log.info("根据单元ID列表获取详细地址，单元ID列表：{}", unitIds);
        
        try {
            List<AddressInfoDTO> addressInfoList = new ArrayList<>();
            
            for (Long unitId : unitIds) {
                AddressInfoDTO addressInfo = getAddressByUnitId(unitId);
                if (addressInfo != null) {
                    addressInfoList.add(addressInfo);
                }
            }
            
            log.info("根据单元ID列表获取详细地址成功，单元ID列表：{}，获取到{}个地址", unitIds, addressInfoList.size());
            return addressInfoList;

        } catch (Exception e) {
            log.error("根据单元ID列表获取详细地址失败，单元ID列表：{}", unitIds, e);
            return new ArrayList<>();
        }
    }

    @Override
    @Cacheable(value = "address:byBuildingIds", key = "#buildingIds.hashCode()", unless = "#result == null || #result.isEmpty()")
    public List<AddressInfoDTO> getAddressesByBuildingIds(List<Long> buildingIds) {
        log.info("根据楼栋ID列表获取详细地址，楼栋ID列表：{}", buildingIds);
        
        try {
            List<AddressInfoDTO> addressInfoList = new ArrayList<>();
            
            for (Long buildingId : buildingIds) {
                AddressInfoDTO addressInfo = getAddressByBuildingId(buildingId);
                if (addressInfo != null) {
                    addressInfoList.add(addressInfo);
                }
            }
            
            log.info("根据楼栋ID列表获取详细地址成功，楼栋ID列表：{}，获取到{}个地址", buildingIds, addressInfoList.size());
            return addressInfoList;

        } catch (Exception e) {
            log.error("根据楼栋ID列表获取详细地址失败，楼栋ID列表：{}", buildingIds, e);
            return new ArrayList<>();
        }
    }

    @Override
    @Cacheable(value = "address:byCommunityIds", key = "#communityIds.hashCode()", unless = "#result == null || #result.isEmpty()")
    public List<AddressInfoDTO> getAddressesByCommunityIds(List<Long> communityIds) {
        log.info("根据社区ID列表获取详细地址，社区ID列表：{}", communityIds);
        
        try {
            List<AddressInfoDTO> addressInfoList = new ArrayList<>();
            
            for (Long communityId : communityIds) {
                AddressInfoDTO addressInfo = getAddressByCommunityId(communityId);
                if (addressInfo != null) {
                    addressInfoList.add(addressInfo);
                }
            }
            
            log.info("根据社区ID列表获取详细地址成功，社区ID列表：{}，获取到{}个地址", communityIds, addressInfoList.size());
            return addressInfoList;

        } catch (Exception e) {
            log.error("根据社区ID列表获取详细地址失败，社区ID列表：{}", communityIds, e);
            return new ArrayList<>();
        }
    }

    /**
     * 构建区域地址
     * 根据区域ID递归查询父节点，构建完整的区域地址
     * 
     * @param regionId 区域ID
     * @return 区域地址字符串
     */
    private String buildRegionAddress(Long regionId) {
        if (regionId == null) {
            return "";
        }

        try {
            List<String> regionNames = new ArrayList<>();
            Long currentRegionId = regionId;

            // 递归查询父节点，最多查询5层（省市区街道）
            for (int i = 0; i < 5; i++) {
                Region region = regionMapper.selectById(currentRegionId);
                if (region == null) {
                    break;
                }

                regionNames.add(0, region.getRegionName()); // 插入到列表开头

                // 如果到达顶级节点，停止查询
                if (region.getParentId() == null || region.getParentId() == 0) {
                    break;
                }

                currentRegionId = region.getParentId();
            }

            return String.join("", regionNames);

        } catch (Exception e) {
            log.error("构建区域地址失败，区域ID：{}", regionId, e);
            return "";
        }
    }

    /**
     * 构建完整地址
     * 
     * @param regionAddress 区域地址
     * @param communityName 社区名称
     * @param buildingNo 楼栋号
     * @param unitNo 单元号
     * @param roomNumber 房间号
     * @return 完整地址
     */
    private String buildFullAddress(String regionAddress, String communityName, 
                                   String buildingNo, String unitNo, String roomNumber) {
        StringBuilder addressBuilder = new StringBuilder();
        
        // 添加区域地址
        if (StringUtils.hasText(regionAddress)) {
            addressBuilder.append(regionAddress);
        }
        
        // 添加社区名称
        if (StringUtils.hasText(communityName)) {
            if (addressBuilder.length() > 0) {
                addressBuilder.append("");
            }
            addressBuilder.append(communityName);
        }
        
        // 添加楼栋号
        if (StringUtils.hasText(buildingNo)) {
            if (addressBuilder.length() > 0) {
                addressBuilder.append("");
            }
            addressBuilder.append(buildingNo).append("栋");
        }
        
        // 添加单元号
        if (StringUtils.hasText(unitNo)) {
            if (addressBuilder.length() > 0) {
                addressBuilder.append("");
            }
            addressBuilder.append(unitNo).append("单元");
        }
        
        // 添加房间号
        if (StringUtils.hasText(roomNumber)) {
            if (addressBuilder.length() > 0) {
                addressBuilder.append("");
            }
            addressBuilder.append(roomNumber).append("号");
        }
        
        return addressBuilder.toString();
    }

    /**
     * 获取区域名称
     * 
     * @param regionId 区域ID
     * @return 区域名称
     */
    private String getRegionName(Long regionId) {
        if (regionId == null) {
            return "";
        }

        try {
            Region region = regionMapper.selectById(regionId);
            return region != null ? region.getRegionName() : "";
        } catch (Exception e) {
            log.error("获取区域名称失败，区域ID：{}", regionId, e);
            return "";
        }
    }
} 